#include "backtrace.h"
#include "log.h"

#include <execinfo.h>
#include <sstream>
#include <iostream>

//获取当前的调用栈
//bt 保存调用栈 //size 最多返回层数 //skip 跳过栈顶的层数
void Backtrace(std::vector<std::string>& bt, int size, int skip)
{
    void** array = (void**)malloc((sizeof(void*) * size));

    //backtrace用于在程序崩溃时获取程序堆栈信息
    //buffer：指向指针数组的指针，用于存储堆栈跟踪信息。
    //size：指定存储堆栈跟踪信息的最大帧数。
    //函数会将调用堆栈的返回地址依次存储到buffer指向的数组中，直到达到指定的最大帧数或者堆栈信息已经全部存储完毕。
    //函数返回实际存储的帧数 失败返回负数
    //因为backtrace()函数通常不是在当前代码文件中定义的，而是在操作系统提供的动态库中实现的，所以需要使用作用域运算符来明确指定函数的全局作用域。在这种情况下，使用::backtrace()可以确保调用的是全局作用域中的backtrace()函数。
    size_t s = ::backtrace(array, size);
    

    //backtrace_symbols用于将backtrace()函数获取到的堆栈跟踪信息转换为可读字符串
    //buffer：指向指针数组的指针，这个指针数组包含由backtrace()获取的堆栈跟踪信息。
    //size：指定buffer数组中包含的帧数。
    //函数返回一个字符串数组，每个字符串表示一个函数调用的堆栈信息  失败返回NULL
    char** strings = backtrace_symbols(array, s);
    if(NULL == strings)
    {
        log_error("backtrace_synbols error");
        free(array);
        return;
    }

    for(size_t i = skip; i < s; ++i)
    {
        //bt.push_back(demangle(strings[i]));
        bt.push_back(strings[i]);
    }

    free(strings);
    free(array);
}

//获取当前栈信息的字符串
//size 栈的最大层数 //skip 跳过栈顶的层数 //prefix 栈信息前输出的内容
std::string BacktraceToString(int size, int skep, const std::string& prefix)
{   
    std::vector<std::string> bt;
    Backtrace(bt, size, skep);
    std::stringstream ss;
    ss << std::endl;
    for(size_t i = 0; i < bt.size(); ++i)
    {
        ss << prefix << bt.at(i) << std::endl;
    }
    return ss.str();
}